package top.jiangqiang.qyblog.core.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import com.github.yulichang.wrapper.DeleteJoinWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.jiangqiang.qyblog.common.base.query.PageResult;
import top.jiangqiang.qyblog.common.base.response.Result;
import top.jiangqiang.qyblog.common.exception.JsonException;
import top.jiangqiang.qyblog.core.base.service.impl.BaseServiceImpl;
import top.jiangqiang.qyblog.core.domain.dto.CategoryAddDto;
import top.jiangqiang.qyblog.core.domain.dto.CategoryQueryDto;
import top.jiangqiang.qyblog.core.domain.dto.CategoryUpdateDto;
import top.jiangqiang.qyblog.core.domain.entity.ArticleCategory;
import top.jiangqiang.qyblog.core.domain.entity.Category;
import top.jiangqiang.qyblog.core.domain.vo.CategoryVo;
import top.jiangqiang.qyblog.core.mapper.CategoryMapper;
import top.jiangqiang.qyblog.core.service.ICategoryService;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 文章分类 服务实现类
 * </p>
 *
 * @author JiangQiang
 * @since 2023-05-29
 */
@Service
public class CategoryServiceImpl extends BaseServiceImpl<CategoryMapper, Category> implements ICategoryService {

    /**
     * 将所有分类转换为一个Map，key为parentId，value为相同parentId的一组分类对象
     *
     * @return
     */
    private Map<Long, List<CategoryVo>> getMapGroupByParentId() {
        //所有的分类，分类数量并不会很多，所以直接查完
        List<CategoryVo> categoryVos = getCategoryMPJLambdaWrapper().list(CategoryVo.class);
        if (CollUtil.isNotEmpty(categoryVos)) {
            //根据parentId进行分组，key是parentId，value是相同parentId的分类
            Map<Long, List<CategoryVo>> groupByParentId = categoryVos.stream().collect(Collectors.groupingBy(CategoryVo::getParentId));
            for (CategoryVo categoryVo : categoryVos) {
                //关联成树形结构
                List<CategoryVo> categoryVoList = groupByParentId.get(categoryVo.getId());
                if (CollUtil.isNotEmpty(categoryVoList)) {
                    categoryVo.setChildren(categoryVoList);
                } else {
                    categoryVo.setChildren(new ArrayList<>());
                }
            }
            return groupByParentId;
        } else {
            return new HashMap<>();
        }
    }

    @Override
    public Result<PageResult<CategoryVo>> findByCondition(CategoryQueryDto categoryQueryDto) {
        PageResult<CategoryVo> page = getCategoryMPJLambdaWrapper()
                //查询指定父级菜单下的直接子分类
                .eq(categoryQueryDto.getParentId() != null, Category::getParentId, categoryQueryDto.getParentId())
                .like(StrUtil.isNotBlank(categoryQueryDto.getName()), Category::getName, categoryQueryDto.getName())
                .page(categoryQueryDto.toPage(), CategoryVo.class);

        Map<Long, List<CategoryVo>> groupByParentId = getMapGroupByParentId();
        for (CategoryVo record : page.getRecords()) {
            List<CategoryVo> categoryVoList = groupByParentId.get(record.getId());
            if (CollUtil.isNotEmpty(categoryVoList)) {
                record.setChildren(categoryVoList);
            } else {
                record.setChildren(new ArrayList<>());
            }
        }
        return Result.ok(page);
    }

    /**
     * 构造查询片段，查询标签相关属性以及该标签下文章数量
     *
     * @return
     */
    private MPJLambdaWrapper<Category> getCategoryMPJLambdaWrapper() {
        return lambdaJoinWrapper()
                .selectAll(Category.class)
                .selectSub(ArticleCategory.class,
                        wrapper -> wrapper.selectCount(ArticleCategory::getId).eq(ArticleCategory::getCategoryId, Category::getId),
                        CategoryVo::getArticleCount)
                ;
    }

    @Override
    public Result<CategoryVo> saveCategory(CategoryAddDto categoryAddDto) {
        String name = categoryAddDto.getName();
        Category category = lambdaQuery().eq(Category::getName, name).one();
        if (category != null) {
            throw new JsonException("分类名称不允许重复");
        }
        //不可能为空字符串
        String path = categoryAddDto.getAlias();
        category = lambdaQuery().eq(Category::getAlias, path).one();
        if (category != null) {
            throw new JsonException("分类路径不允许重复");
        }
        category = typeConverter.convert(categoryAddDto, Category.class);
        baseMapper.insert(category);
        return getCategory(category.getId());
    }

    @Override
    public Result<CategoryVo> editCategory(CategoryUpdateDto categoryUpdateDto) {
        Long categoryId = categoryUpdateDto.getId();
        if (getById(categoryId) == null) {
            throw new JsonException("分类不存在");
        }
        String name = categoryUpdateDto.getName();
        Category category = lambdaQuery().eq(Category::getName, name).one();
        if (category != null && !category.getId().equals(categoryId)) {
            throw new JsonException("分类名称不允许重复");
        }
        String path = categoryUpdateDto.getAlias();
        category = lambdaQuery().eq(Category::getAlias, path).one();
        if (category != null && !category.getId().equals(categoryId)) {
            throw new JsonException("分类路径不允许重复");
        }
        category = typeConverter.convert(categoryUpdateDto, Category.class);
        baseMapper.updateById(category);
        return getCategory(categoryId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> deleteCategory(Long id) {
        //查询子分类数量
        if (lambdaQuery().eq(Category::getParentId, id).count() != 0) {
            return Result.error("该分类下存在子分类，不允许删除");
        }
        DeleteJoinWrapper<Category> deleteJoinWrapper = deleteJoinWrapper().deleteAll()
                .leftJoin(ArticleCategory.class, ArticleCategory::getCategoryId, Category::getId)
                .eq(Category::getId, id);
        deleteJoin(deleteJoinWrapper);
        return Result.ok();
    }

    @Override
    public Result<CategoryVo> getCategory(Long id) {
        return Result.ok(getCategoryVoWithChildren(id));
    }

    @Override
    public CategoryVo getCategoryByCategoryName(String categoryName) {
        return getCategoryMPJLambdaWrapper().eq(Category::getName, categoryName).one(CategoryVo.class);
    }

    @Override
    public Long saveCategory(String categoryName) {
        //别名为空，生成不重复的别名
        String alias = PinyinUtil.getPinyin(categoryName, "-");
        //likeRight 查询别名 获取所有以alias为开头的别名
        List<Category> categoryList = lambdaQuery().likeRight(Category::getAlias, alias).list();
        if (CollUtil.isNotEmpty(categoryList)) {
            List<String> aliasList = categoryList.stream().map(Category::getAlias).toList();
            String tmpAlias = alias;
            while (aliasList.contains(tmpAlias)) {
                tmpAlias = alias + RandomUtil.randomNumbers(5);
            }
            alias = tmpAlias;
        }
        Category category = new Category();
        category.setName(categoryName);
        category.setAlias(alias);
        baseMapper.insert(category);
        return category.getId();
    }

    /**
     * 获取指定id的分类，并且已经关联上对应分类的子分类
     *
     * @param id 指定分类id
     * @return
     */
    @NotNull
    private CategoryVo getCategoryVoWithChildren(Long id) {
        CategoryVo categoryVo = getCategoryMPJLambdaWrapper().eq(Category::getId, id).one(CategoryVo.class);
        if (categoryVo == null) {
            throw new JsonException("分类不存在");
        }
        Map<Long, List<CategoryVo>> groupByParentId = getMapGroupByParentId();
        List<CategoryVo> categoryVoList = groupByParentId.get(id);
        if (CollUtil.isNotEmpty(categoryVoList)) {
            categoryVo.setChildren(categoryVoList);
        } else {
            categoryVo.setChildren(new ArrayList<>());
        }
        return categoryVo;
    }
}
